package waggle.client;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.user.client.rpc.IsSerializable;

public class Query<Q> implements IsSerializable {
	
	public Query() {
		this(-1, -1);
	}

	public Query(int start, int limit) {
		this.start = start;
		this.limit = limit;
	}

	//數字組
	
	public static int UNLIMITED = -2;
	/**
	 * Number of records count of this query without limit.
	 * 
	 * Negative if the query does not count.
	 */
	protected int count = -1;

	protected boolean countTotalResults = true;

	/**
	 * The maximum number of records to return for this query.
	 */
	protected int limit = 100;

	/**
	 * The record number to start the query at.
	 */
	protected int start = 1;

	/**
	 * Gets Number of records count of this query without limit.
	 * 
	 * Negative if the query does not count.
	 * 
	 * @return count as long
	 */
	public int getCount() {
		return count;
	}

	/**
	 * Gets the limit.
	 * 
	 * @return the limit
	 */
	public int getLimit() {
		return limit;
	}

	/**
	 * Sets the start.
	 * 
	 * @param newStart
	 */
	public void setStart(int newStart) {
		start = newStart;
	}

	/**
	 * Gets the start.
	 * 
	 * @return the start
	 */
	public int getStart() {
		return start;
	}


	/**
	 * 
	 * @return
	 */
	public boolean isCountTotalResults() {
		return countTotalResults;
	}

	/**
	 * Sets number records of this search without limit.
	 * 
	 * @param count
	 *            long
	 */
	public void setCount(int count) {
		this.count = count;
	}

	public void setCountTotalResults(boolean counted) {
		this.countTotalResults = counted;
	}

	/**
	 * @param limit
	 *            the limit to set
	 */
	public void setLimit(int limit) {
		this.limit = limit;
	}
	
	//搜尋條件組

	//搜尋關鍵字也寫在這邊
	/**
	 * The set of query search filters i.e AcceptedSpecies = blah, BasicOfRecord
	 * = foo, ...
	 * 
	 * This filters is difference from {@link #baseFilters} for memory tokens
	 * purpose.
	 */
	protected Set<String> searchFilters = null;

	/**
	 * Adds a filter to this query. A valid filter takes the following form:
	 * 
	 * "concept <operator> value"
	 * 
	 * where concept can match any of the concept names found in the Darwin
	 * Core, the Curatorial Extension, and the Geospatial Extension, and
	 * operator is either '=' or 'like'. For example, "Genus like Coeliades" or
	 * "DecimalLatitude = 38.4332345" are valid filters.
	 * 
	 * Filters can be chained like this:
	 * 
	 * OccurrenceQuery q = new OccurrenceQuery();
	 * q.addFilter("Genus = Coeliades"
	 * ).addFilter("DecimalLatitude = 38.4332345");
	 * 
	 * @param filter
	 *            the query filter to add
	 * @return the query object
	 */
	public void addSearchFilter(String searchFilter) {
		if (searchFilters == null) {
			searchFilters = new HashSet<String>();
		}
		searchFilters.add(searchFilter);
	}

	public void clearSearchFilter() {
		if (searchFilters != null) {
			searchFilters.clear();
		}
	}

	public Set<String> getSearchFilters() {
		if (searchFilters == null) {
			searchFilters = new HashSet<String>();
		}
		return searchFilters;
	}

	public void setSearchFilters(Set<String> searchFilters) {
		this.searchFilters = searchFilters;
	}
	
	/**
	 * The set of query updates of the form "Concept = Value".
	 */
	protected Set<String> updates;
	
	public Query<Q> addUpdate(String update) {
		if (updates == null) {
			updates = new HashSet<String>();
		}
		updates.add(update);
		return this;
	}
	/**
	 * @return the updates
	 */
	public Set<String> getUpdates() {
		return updates;
	}

	/**
	 * @param updates
	 *            the updates to set
	 */
	public void setUpdates(Set<String> updates) {
		this.updates = updates;
	}

	
	//排序方式
	protected Map<String, Boolean> orderingMap = new HashMap<String, Boolean>();
	public void addOrdering(String property, Boolean isAscending) {
		orderingMap.put(property, isAscending);
	}
	
	public Map<String, Boolean> getOrderingMap() {
		return orderingMap;
	}
	
	//搜尋結果
	
	/**
	 * The query results.
	 */
	protected List<Q> results;

	/**
	 * Gets the results
	 * 
	 * @return the set of {@link Occurrence} objects
	 */
	public List<Q> getResults() {
		return results;
	}

	/**
	 * Sets the query results.
	 * 
	 * @param results
	 *            a set of {@link Occurrence} objects
	 */
	public void setResults(List<Q> results) {
		this.results = results;
	}


	public String toString() {
		StringBuilder out = new StringBuilder();
		out.append("start=" + start + ";limit=" + limit);
		if (searchFilters != null) {
			for (String filter : searchFilters) {
				out.append(";filter=" + filter);
			}
		}
		return out.toString();
	}

}
